#include "NUChat.h"

NUChat::NUChat(void)
{
	init();
	startupScreen(false);
}

NUChat::NUChat( std::string ip )
{
	init();
	startupScreen(false);
	establishTCPConnection(ip);
}

NUChat::NUChat(std::string nick, std::string ip)
{
	init();
	startupScreen(false);
	username = nick;
	//asprintf(&username, nick);
	establishTCPConnection(ip);
}

//Destructor
NUChat::~NUChat( void )
{
	endwin();
}

void NUChat::init()
{
	window = initscr();
	keypad(window, TRUE);
	noecho();
	getmaxyx(window, rows, cols);
	// one line for the tool bar, one for the input line.
	chrome = 2;

	start_color();

#ifdef __WIN32__
	// Allows for non-blocking.
	nodelay(window, TRUE);
	TCHAR name [ UNLEN + 1 ];
	DWORD size = UNLEN + 1;

	if (GetUserName( (TCHAR*)name, &size ))
		username = name;
	else
		username = "n00b_user";
#else
	username = getenv("USER");
#endif
}

void NUChat::resize(void)
{
	drawConversation();
	redrawwin(window);
}

void NUChat::run(void)
{
	Client::run();
}

void NUChat::startupScreen(bool splash)
{
	erase();
	int centered_x = (cols-63)/2;
	int centered_y = (rows-5)/2;

	mvprintw(0+centered_y, centered_x, "    _/      _/  _/    _/    _/_/_/  _/     Version %s    _/    ", PRODUCT_VERSION);
	mvprintw(1+centered_y, centered_x, "   _/_/    _/  _/    _/  _/        _/_/_/      _/_/_/  _/_/_/_/ ");
	mvprintw(2+centered_y, centered_x, "  _/  _/  _/  _/    _/  _/        _/    _/  _/    _/    _/      ");
	mvprintw(3+centered_y, centered_x, " _/    _/_/  _/    _/  _/        _/    _/  _/    _/    _/       ");
	mvprintw(4+centered_y, centered_x, "_/      _/    _/_/      _/_/_/  _/    _/    _/_/_/      _/_/    ");

	move(rows-1, 0);

	refresh();

#ifdef __WIN32__
	if(splash)		Sleep(1);
#else
	if(splash)		sleep(1);
#endif
	else			keyTyped(getch());

	addLine(0, "Hello " + username + "! " + "Welcome to NUChat " + PRODUCT_VERSION + " - Enter /help for command listing.");
}

void NUChat::catchInput(void)
{
	int ch = getch();
	switch(ch)
	{
		case '\n'				: keyEnter();		break;
		case KEY_LEFT			: keyLeft();		break;
		case KEY_RIGHT			: keyRight();		break;
		case KEY_UP				: keyUp();			break;
		case KEY_DOWN			: keyDown();		break;
		case KEY_DELETE			: keyDelete();		break;
//		case KEY_RESIZE			: resize();			break;
		default					: keyTyped(ch);		break;
	}
}

void NUChat::updateToolbar(void)
{
	attron(A_STANDOUT | A_BOLD | A_UNDERLINE);
	for (int i = 0; i < cols; i++)
		mvprintw(0, i, " ");
	if (host != NULL)
		mvprintw(0, 1, "%s %s | Connected as Client to Server %s", PRODUCT_NAME, PRODUCT_VERSION, inet_ntoa(*(in_addr *)host->h_addr));
	else
		mvprintw(0, 1, "%s %s | Running Client. Not connected to any server.", PRODUCT_NAME, PRODUCT_VERSION);
	attroff(A_STANDOUT | A_BOLD | A_UNDERLINE);
}

void NUChat::drawConversation(void)
{
	// Incase user resized window.
	getmaxyx(window, rows, cols);

	Message *message;
	unsigned int msg = scrollPos;
	unsigned long messages = conversation.size();
	unsigned int viewRows = rows - chrome;
	unsigned int row;
	//	unsigned int viewMsgs = messages - scrollPos;

	erase();
	updateToolbar();

	for (unsigned int i = 0; /*top chrome*/ i < viewRows && msg < messages; msg++)
	{
		message = conversation.at(msg);

		// Plus 1 for the toolbar
		row = (i+1);

		// System message
		if(message->speaker == 0)
		{
			attron(A_STANDOUT);
			// Fill background of line
			for (int j = 0; j < cols; j++) mvprintw(row, j, " ");
			// Print line
			mvprintw(row, 1, message->message.c_str());
			attroff(A_STANDOUT);

		// Own message
		} else if(message->speaker == 1)
		{
			mvprintw(row, 0, message->message.c_str());

		// Other message
		} else if(message->speaker == 2)
		{
			attron(A_BOLD);
			mvprintw(row, 0, message->message.c_str());
			attroff(A_BOLD);
		} else
		{
			mvprintw(row, 0, message->message.c_str());
		}

		// TODO: Look for spaces to break on.
		i += (unsigned int)ceil((float)message->message.length() / (float)cols);
	}
	updateWindow();
	//	free(message);
}

void NUChat::addLine(int speaker, std::string m )
{
	unsigned long messages = conversation.size();
	unsigned long viewRows = rows - chrome;
	unsigned long viewMsgs = messages - scrollPos;

	Message *message = new Message();
	message->message = m;
	message->speaker = speaker;

	conversation.push_back(message);

	// We need advanced scrolling here...
	if (viewRows <= viewMsgs)
		scrollPos++;
	drawConversation();

}

void NUChat::clearTextField(void)
{
	for(int i = 0; i < DATA_SIZE; i++) mvdelch(rows-1, 0);
	message[0] = '\0';
	cursor = 0;
	characters = 0;
}

void NUChat::updateWindow(void)
{
	mvprintw(rows-1, 0, message);
	move(rows-1, cursor);
	refresh();
}

void NUChat::keyEnter()
{
	if(strlen(message) == 0)	return;

	if(message[0] == '/')
	{
		processCommands(message);
	} else if (host != NULL)
	{
		handleOutgoingClientMessage();
	}
	clearTextField();
}

void NUChat::keyLeft()
{
	(cursor > 0) ? cursor-- : cursor;
}

void NUChat::keyRight()
{
	(cursor < DATA_SIZE) ? cursor++ : cursor;
}

void NUChat::keyUp()
{
	(scrollPos > 0) ? scrollPos-- : scrollPos;
	drawConversation();
}

void NUChat::keyDown()
{
	unsigned long messages = conversation.size();
	unsigned long viewRows = rows - chrome;
	unsigned long viewMsgs = messages - scrollPos;

	(viewRows < viewMsgs) ? scrollPos++ : scrollPos;
	drawConversation();
}

void NUChat::keyDelete()
{
	if(characters > 0)
	{
		if(cursor == characters)
		{
			mvdelch(rows-1, characters-1);
			message[characters-1] = '\0';
		} else {
			for(int i = cursor-1; i < characters; i++)
			{
				message[i] = message[i+1];
			}
			mvdelch(rows-1, cursor);
		}
		characters--;
		cursor--;
	}
}

void NUChat::keyTyped(int ch)
{
	if(ch < 32 || ch > 127 || characters >= DATA_SIZE)	return;
	characters++;
	if(cursor == characters)
	{
		message[characters] = (char)ch;
	} else {
		for (int i = characters-1; i > cursor; i--)
		{
			message[i+1] = message[i];
		}
		message[cursor] = (char)ch;
	}
	if (characters < DATA_SIZE) message[characters] = '\0';
	cursor++;
}

void NUChat::quit(void)
{
	Client::quit("");
}
